package service.impl;

import common.consts.Accounts;
import common.consts.Balances;
import common.consts.Consts;
import common.consts.Gender;
import dao.*;
import domain.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import service.AccountService;
import service.ServiceResponse;
import service.util.PasswordUtil;
import utils.Ids;
import utils.ImageUtils;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Date;

/**
 * Created by aceyin on 2015/6/1 0001.
 */
@Service
public class AccountServiceImpl extends ServiceBase implements AccountService {

    private static final Logger logger = LoggerFactory.getLogger(AccountServiceImpl.class);
    @Autowired
    private AccountDao accountDao;
    @Autowired
    private UserProfileDao userProfileDao;
    @Autowired
    private UserDataProfileDao userDataProfileDao;
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private UserLocationDao userLocationDao;
    @Autowired
    private BalanceDao balanceDao;


    @Override
    @Transactional(readOnly = false)
    public ServiceResponse login(String username, String password, String ip) {
        Account account = accountDao.findByUsername(username);
        if (account == null) {
            return ServiceResponse.fail(Consts.i18nKey.USERNAME_NOT_EXIST);
        }
        String md5 = PasswordUtil.encrypt(password);
        if (StringUtils.equalsIgnoreCase(md5, account.getPassword())) {
            // update user data profile
            long id = account.getId();
            UserDataProfile dataProfile = userDataProfileDao.get(id);
            Integer loginTimes = dataProfile.getLoginTimes();
            dataProfile.setLoginTimes(loginTimes + 1);
            userDataProfileDao.update(dataProfile);

            UserProfile profile = userProfileDao.get(id);

            accountDao.updateAccountStatus(id, Accounts.Status.NORMAL);

            return ServiceResponse.success()
                    .with("id", account.getId())
                    .with("nick", account.getNick())
                    .with("avatar", account.getAvatar())
//                    .with("status", account.getStatus())
                    .withTemp("password", account.getPassword())
                    .with("profile", profile);
        }
        return ServiceResponse.fail(Consts.i18nKey.PASSWORD_INCORRECT);
    }

    @Override
    @Transactional(readOnly = false)
    public ServiceResponse register(Account acc) {
        String username = acc.getUsername();
        Account account = accountDao.findByUsername(username);
        if (account != null) {
            return ServiceResponse.fail(Consts.i18nKey.ACCOUNT_ALREADY_EXIST);
        }

        long id = Ids.get(username);
        account = new Account();
        account.setId(id);
        account.setCreateTime(new Date());
        account.setLatestUse(new Date());
        account.setPassword(PasswordUtil.encrypt(acc.getPassword()));
        account.setUsername(username);
        account.setType(acc.getType());
        account.setStatus(Accounts.Status.NORMAL.name());
        accountDao.insert(account);

        //插入默认的user profile信息
        UserProfile profile = new UserProfile();
        profile.setId(id);
        profile.setPhone(username);
        profile.setGender(Gender.FEMALE.name());
        userProfileDao.insert(profile);

        // 插入一条空的data profile信息
        UserDataProfile dataProfile = new UserDataProfile();
        dataProfile.setId(id);
        userDataProfileDao.insert(dataProfile);

        //插入一条空的公司信息,因为用户可以在 商家版 和 用户版 之间切换
        //为了避免从用户版切回商家版的时候，没有商家信息，所以这里需要预先插入一条
        Company company = new Company();
        company.setName("");
        company.setAddress("");
        company.setCity("");
        company.setDescription("");
        company.setDistrict("");
        company.setTradeCategory("");
        company.setLatitude(0d);
        company.setLongitude(0d);
        company.setOwner(id);
        company.setProvince("");
        companyDao.insert(company);

        // 插入一条空的 user_location
        UserLocation location = new UserLocation();
        location.setId(id);
        location.setUpdateTime(new Date());
        location.setProvince("");
        location.setCity("");
        location.setDistrict("");
        location.setStreet("");
        location.setLongitude(0d);
        location.setLatitude(0d);
        location.setUpdateTime(new Date());
        userLocationDao.insert(location);

        // 插入一条账户余额
        Balance balance = new Balance();
        balance.setId(id);
        balance.setCash(0f);
        balance.setMonthlyFee(0);
        balance.setStatus(Balances.Status.NORMAL.name());
        balance.setUpdateTime(new Date());
        balance.setYearlyFee(0);
        balanceDao.insert(balance);
        return ServiceResponse.success();
    }

    @Override
    @Transactional(readOnly = false)
    public ServiceResponse resetPassword(String mobile, String password) {
        Account account = accountDao.findByUsername(mobile);
        if (account == null) {
            return ServiceResponse.fail(Consts.i18nKey.UNKNOWN_USER);
        }

        String pwd = PasswordUtil.encrypt(password);
        accountDao.updatePassword(account.getId(), pwd);
        return ServiceResponse.success();
    }

    @Override
    @Transactional
    public ServiceResponse uploadAvatar(long id, InputStream is) {
        Account account = accountDao.get(id);
        if (account == null) {
            return ServiceResponse.fail(Consts.i18nKey.UNKNOWN_USER);
        }
        try {
            String fileUrl = storeFile(is, id);
            accountDao.updateAvatar(fileUrl, id);
            return ServiceResponse.success().with("avatar", fileUrl);
        } catch (Exception e) {
            e.printStackTrace();
            return ServiceResponse.fail(Consts.i18nKey.SYSTEM_ERROR);
        }
    }


    /**
     * 读取网络文件流
     */
    private String storeFile(InputStream fis, long id) throws Exception {
        String separator = "/";
        String destFormat = Consts.USER_AVATAR_FILE_TYPE;
        String suffix = "." + destFormat;

        String path = Consts.USER_AVATAR_BASE_PATH + separator + id + suffix;

        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(path);
            boolean flag = ImageUtils.convertFormat(fis, fos, destFormat, 0, 0);
            if (flag == false) {
                throw new RuntimeException("format avatar file failed.");
            }
            fos.flush();
            fos.close();
            fis.close();
        } catch (Exception ex) {
            logger.error("upload avatar file failed.", ex);
            if (fos != null) {
                fos.close();
            }
            if (fis != null) {
                fis.close();
            }
            throw ex;
        }
        return path;
    }

    @Override
    @Transactional(readOnly = false)
    public ServiceResponse changePassword(long id, String opassword, String password) {
        Account account = accountDao.get(id);
        if (account == null) {
            return ServiceResponse.fail(Consts.i18nKey.UNKNOWN_USER);
        }

        String md5 = PasswordUtil.encrypt(opassword);
        if (!md5.equalsIgnoreCase(account.getPassword())) {
            return ServiceResponse.fail(Consts.i18nKey.ORIGINAL_PASSWORD_IS_WRONG);
        }

        String newPwd = PasswordUtil.encrypt(password);

        accountDao.updatePassword(account.getId(), newPwd);

        return ServiceResponse.success();
    }

    public void setUserDataProfileDao(UserDataProfileDao userDataProfileDao) {
        this.userDataProfileDao = userDataProfileDao;
    }

    public void setCompanyDao(CompanyDao companyDao) {
        this.companyDao = companyDao;
    }

    public void setUserLocationDao(UserLocationDao userLocationDao) {
        this.userLocationDao = userLocationDao;
    }

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void setUserProfileDao(UserProfileDao userProfileDao) {
        this.userProfileDao = userProfileDao;
    }

    public void setBalanceDao(BalanceDao balanceDao) {
        this.balanceDao = balanceDao;
    }
}
